#pragma once
#include<iostream>
#include<fstream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cstdarg>
#include<sys/types.h>
#include<unistd.h>
#include<pthread.h>
#include"LockGuard.hpp"

bool gIsSave = false;
const std::string logname = "log.txt";

enum Level
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

void Savefile(const std::string filename ,const std::string &message)
{
    std::ofstream out(filename,std::ios::app);
    if(!out.is_open())
    {
        return;
    }
    out<<message;
    out.close();
}
std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
      return "debug";
    case INFO:
      return "info";
    case WARNING:
      return "warning";
    case ERROR:
      return "error";
    case FATAL:
      return "fatal";
    default:
        return "Unknown";
    }
}
std::string GettimeString()
{
    time_t curr_time = time(nullptr);
    struct tm *format_time = localtime(&curr_time);
    if(format_time==nullptr)
    {
      return "None";
    }
    char time_buffer[1024];
    snprintf(time_buffer,sizeof(time_buffer),"%d-%d-%d %d:%d:%d",
            format_time->tm_year+1900,
            format_time->tm_mon+1,
            format_time->tm_mday,
            format_time->tm_hour,
            format_time->tm_min,
            format_time->tm_sec);
            return time_buffer;
}
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void LogMessage(std::string filename,int line,bool issave,int level,const char *format,...)
{
    std::string levelstr = LevelToString(level);
    std::string timestr = GettimeString();
    pid_t selfid = getpid();
    
    char buffer[1024];
    va_list arg;
    va_start(arg,format);
    vsnprintf(buffer,sizeof(buffer),format,arg);
    va_end(arg);
    std::string message ="["+timestr+"]"+"["+levelstr+"]"+"["+std::to_string(selfid)+"]"
    +"["+filename+"]"+"["+std::to_string(line)+"]"+buffer;
    LockGurad Lockgurad(&lock);
  if(!issave)
  {
    std::cout<<message;
  }
  else
  {
    Savefile(logname,message);
  }
}

#define LOG(level, format,...)                                            \
  do                                                                      \
  {                                                                       \
    LogMessage(__FILE__, __LINE__, gIsSave, level, format, ##__VA_ARGS__); \
  } while (0)
#define EnableFile() \
  do                 \
  {                  \
    gIsSave = true    \
  } while (0)
#define EnableScreen() \
  do                   \
  {                    \
    gIsSave = false;    \
  } while (0);